package name.marz.to.go.ahg;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;

import name.marz.to.go.ahg.common.cli.OutFileOption;
import name.marz.to.go.ahg.common.cli.PasswordOption;
import name.marz.to.go.ahg.common.util.HttpUtil;
import name.marz.to.go.ahg.common.util.LogUtil;
import name.marz.to.go.ahg.core.AbstractAutoGetterMain;
import name.marz.to.go.ahg.core.AutoGetterHttpClient;
import name.marz.to.go.ahg.core.exception.InvalidDocumentException;
import name.marz.to.go.ahg.core.exception.UnknownClientException;
import name.marz.to.go.ahg.core.exception.UserProcessException;
import name.marz.to.go.ahg.core.executer.AbstractLoginExecuter;
import name.marz.to.go.ahg.core.executer.DocumentGetExecuter;
import name.marz.to.go.ahg.mhbk.executer.MHBKDealDetailExecuter;
import name.marz.to.go.ahg.mhbk.executer.MHBKDetailDownloader;
import name.marz.to.go.ahg.mhbk.executer.MHBKEntryClientSequenceExecuter;
import name.marz.to.go.ahg.mhbk.executer.MHBKLoginExecuter;
import name.marz.to.go.ahg.mhbk.executer.MHBKTopPageExecuter;
import name.marz.to.go.ahg.mhbk.executer.MHBKUserNumberExecuter;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class MHBKAccountGetMain extends AbstractAutoGetterMain {
	private static final Logger log = Logger.getLogger(MHBKAccountGetMain.class.getName());
	private static final String DEFAULT_MEISAI_FILENAME="meisai.csv";
	AutoGetterHttpClient client = new AutoGetterHttpClient();
	private File cookieFile = new File("mhbk.cookie");
	
	String userNum;
	private String password;
	private File outFile;
	private URI baseUri;
	
	/**
	 * 
	 */
	public MHBKAccountGetMain() {
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MHBKAccountGetMain main = new MHBKAccountGetMain();
		main.Main(args);
	}
	
	@Override
	protected void ready() throws Exception {
		loadCookie();
		LogUtil.log(Level.FINE, client.getCookieStore().getCookies());
		baseUri = HttpUtil.createURISafety("https://web.ib.mizuhobank.co.jp/servlet/LOGBNK0000000B.do");
	}
	
	private void loadCookie() throws IOException, ClassNotFoundException {
		CookieStore store = client.getCookieStore();
		store.clear();
		HttpUtil.loadCookie(cookieFile, store);
	}
	
	@Override
	public Document goTopPage() throws ClientProtocolException, IOException,
			UserProcessException {
		URI uri = HttpUtil.createURISafety("http://www.mizuhobank.co.jp/direct/start.html");
		MHBKTopPageExecuter e = new MHBKTopPageExecuter(uri, client);
		Document doc = e.execute();
		LogUtil.log(Level.FINE, client.getCookieStore().getCookies());
		return doc;
	}

	@Override
	public Document doLogin(Document doc) throws ClientProtocolException,
			IOException, UserProcessException {
		log.info("お客様番号入力処理開始");
		final String FORM_ID="LOGBNK_00000B";
		Elements es = doc.getElementsByTag("form").select("[name="+FORM_ID+"]");
		if ( es.isEmpty() )  throw new InvalidDocumentException("FORM "+FORM_ID+"が見つかりません",doc);
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),es.first().attr("action"));
		MHBKUserNumberExecuter userNumExec = new MHBKUserNumberExecuter(uri, client, doc, userNum);
		try {
			doc = userNumExec.execute();
			LogUtil.log(Level.FINE, client.getCookieStore().getCookies());
//			log.fine("userNum response source="+doc.html());
		} catch (UnknownClientException e) {
			log.info("未登録端末です。"+e.getMessage());
			log.info("端末登録を開始します。");
			MHBKEntryClientSequenceExecuter entryexec = new MHBKEntryClientSequenceExecuter(getBaseUri(e.getDocument()), client, e.getDocument());
			doc = entryexec.execute();
		}
		log.info("お客様番号入力処理終了");
		
		log.info("暗証番号入力処理開始");
		baseUri = getBaseUri(doc);
		final Document loginSrcDoc = doc;
		LogUtil.log(Level.FINE, HttpUtil.getParametersFromInputTags(loginSrcDoc), "password page params");
		final String FORM_ID2="LOGBNK_00005B";
		es = doc.getElementsByTag("form").select("[name="+FORM_ID2+"]");
		if ( es.isEmpty() )  throw new InvalidDocumentException("FORM "+FORM_ID2+"が見つかりません",doc);
		uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority()
										,HttpUtil.getFormActionString(doc, FORM_ID2));
		AbstractLoginExecuter le = new MHBKLoginExecuter(uri, client, doc);
		le.setUserPass(password);
		doc = le.execute();
		LogUtil.log(Level.FINE, HttpUtil.getParametersFromInputTags(loginSrcDoc), "main page params");
		log.info("暗証番号入力処理終了");
		return doc;
	}

	private URI getBaseUri(Document doc) {
		Elements base = doc.getElementsByTag("base");
		if ( base == null ) throw new InvalidDocumentException("no base tag",doc);
		String href = base.first().attr("href");
		if ( href == null ) throw new InvalidDocumentException("no base href",doc);
		URI dummyUri = HttpUtil.createURISafety(href);
		return HttpUtil.createURISafety(dummyUri.getScheme(),dummyUri.getAuthority().replace(":443", ""),"/");
	}

	@Override
	public Document goDownloadPage(Document doc)
			throws ClientProtocolException, IOException, UserProcessException {
		// 入出金明細照会
		log.info("入出金明細照会 開始");
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),"/servlet/MENSRV0100003B.do");
		MHBKDealDetailExecuter de = new MHBKDealDetailExecuter(uri, client,doc);
		doc = de.execute();
		log.info("入出金明細照会 終了");
		return doc;
	}

	@Override
	public File doDownload(Document doc) throws ClientProtocolException,
			IOException, UserProcessException {
		log.info("明細のダウンロードとCSV変換 開始");
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),"/servlet/ACCHST0400001B.do");
		MHBKDetailDownloader dl = new MHBKDetailDownloader(uri,client, doc,  outFile);
		File f = dl.execute();
		log.info("明細のダウンロードとCSV変換 終了");
		
		return f;
	}

	@Override
	public void doLogout(Document doc) throws ClientProtocolException, IOException, UserProcessException {
		Elements es = doc.getElementsByTag("img").select("[alt=ログアウト]");
		if ( es.isEmpty() ) throw new InvalidDocumentException("ログアウトのimgタグが見つかりません", doc);
		String s = es.first().parent().attr("href");
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),s);
		log.finer("logout uri="+uri);
		DocumentGetExecuter executer = new DocumentGetExecuter(uri, client);
		executer.setCharset("UTF-8");
		executer.setPageName("logout");
		doc = executer.execute();
		log.finest("logout response="+doc.html());
	}

	/* (non-Javadoc)
	 * @see name.marz.to.go.ahg.core.AbstractMain#finish()
	 */
	@Override
	protected void finish() {
		super.finish();
		// クッキー保存
		try {
			HttpUtil.saveCookie(client.getCookieStore(), cookieFile);
			log.info("クッキーを保存しました。"+cookieFile);
		} catch (IOException e) {
			log.log(Level.WARNING,"クッキーが保存できませんでした",e);
		}
		// 終了処理
		client.getConnectionManager().shutdown();
	}
	
	@SuppressWarnings("static-access")
	@Override
	protected Options getOptions() {
		Options options = new Options();
		Option out = new OutFileOption(false);options.addOption(out);
		options.addOption(OptionBuilder.hasArg(true).withArgName("number")
				.isRequired(true).withDescription("お客様番号(ご利用カードで確認可)")
				.create("user"));
		Option password = new PasswordOption(true); options.addOption(password);
		return options;
	}

	@Override
	protected void setParams(CommandLine cmd) {
		userNum = cmd.getOptionValue("user");
		this.password = cmd.getOptionValue(PasswordOption.OPT);
		outFile = new File(cmd.getOptionValue(OutFileOption.OPT, DEFAULT_MEISAI_FILENAME));
	}

}
